﻿/*
 * This file is part of CommunitySettlers.
 *
 * CommunitySettlers is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.

 * CommunitySettlers is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with CommunitySettlers.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * Author: Christoph Husse
 * 
 * Also checkout our homepage: http://communitysettlers.codeplex.com/
 */
using System;
using System.Text;
using System.Runtime.Serialization;
using System.IO;
using System.Xml;
using System.Runtime.Serialization.Formatters.Binary;

namespace SettlersEngine
{
    internal static class Serialization
    {
        internal static Boolean EqualsByteWise<T>(this T x, T y)
        {
            if (y == null)
                return false;

            BinaryFormatter format = new BinaryFormatter();
            MemoryStream streamX = new MemoryStream();
            MemoryStream streamY = new MemoryStream();

            format.Serialize(streamX, x);
            format.Serialize(streamY, y);

            if (streamX.Length != streamY.Length)
                return false;

            byte[] arrayX = streamX.ToArray();
            byte[] arrayY = streamY.ToArray();

            for (int i = 0; i < arrayX.Length; i++)
            {
                if (arrayX[i] != arrayY[i])
                    return false;
            }

            return true;
        }

        internal static T CloneByteWise<T>(this T x) where T : class, new()
        {
            BinaryFormatter format = new BinaryFormatter();
            MemoryStream stream = new MemoryStream();

            format.Serialize(stream, x);

            stream.Position = 0;

            return (T)format.Deserialize(stream);
        }


        internal static void Serialize<T>(this T inThis, String inTargetFile, String inRootName, String inNamespace) where T : class
        {
            Directory.CreateDirectory(Path.GetDirectoryName(inTargetFile));

            File.Delete(inTargetFile);

            Stream target = File.OpenWrite(inTargetFile);

            using (target)
            {
                Serialize(inThis, target, inRootName, inNamespace);
            }
        }

        internal static void Serialize<T>(this T inThis, Stream inTarget, String inRootName, String inNamespace) where T : class
        {
            XmlWriter writer = XmlWriter.Create(inTarget, new XmlWriterSettings()
            {
                Encoding = Encoding.UTF8,
                ConformanceLevel = ConformanceLevel.Document,
                Indent = true,
                OmitXmlDeclaration = true,
            });

            using (writer)
            {
                DataContractSerializer serializer = new DataContractSerializer(inThis.GetType(), inRootName, inNamespace);

                serializer.WriteObject(writer, inThis);

                writer.Flush();
            }
        }

        internal static T Deserialize<T>(this T inThis, String inTargetFile, String inRootName, String inNamespace) where T : class, new()
        {
            T result = DeserializeOrNull(inThis, inTargetFile, inRootName, inNamespace);

            if (result == null)
                return new T();

            return result;
        }

        internal static T Deserialize<T>(this T inThis, Stream inSource, String inRootName, String inNamespace) where T : class
        {
            XmlReader reader = XmlReader.Create(inSource);

            using (reader)
            {
                DataContractSerializer serializer = new DataContractSerializer(inThis.GetType(), inRootName, inNamespace);

                return (T)serializer.ReadObject(reader);
            }
        }

        internal static T DeserializeOrNull<T>(this T inThis, String inTargetFile, String inRootName, String inNamespace) where T : class
        {
            if (File.Exists(inTargetFile))
            {
                Stream source = File.OpenRead(inTargetFile);

                using (source)
                {
                    return Deserialize(inThis, source, inRootName, inNamespace);
                }
            }
            else
                return null;
        }
    }

}
